package com.manage.common.core.aspect;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.manage.common.core.annotation.CheckParam;
import com.manage.common.core.result.JsonResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 参数校验 切面
 *
 * @author cipher
 * @date 2017/11/7
 */
//@Aspect
//@Component
public class CheckParamAspect {

    /**
     * 判断是否符合参数规则
     *
     * @param method    方法
     * @param arguments 方法参数
     * @return 是否符合
     */
    public static Boolean isCheck(Method method, Object[] arguments, Class<? extends Annotation> annotationClass) {
        Boolean isCheck = Boolean.TRUE;
        // 只允许有一个参数
        if (!method.isAnnotationPresent(annotationClass)
                || arguments == null) {
            isCheck = Boolean.FALSE;
        }
        return isCheck;
    }

    /**
     * 获取方法
     *
     * @param joinPoint ProceedingJoinPoint
     * @return 方法
     */
    public static Method getMethod(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (method.getDeclaringClass().isInterface()) {
            try {
                method = joinPoint
                        .getTarget()
                        .getClass()
                        .getDeclaredMethod(joinPoint.getSignature().getName(),
                                method.getParameterTypes());
            } catch (SecurityException | NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return method;
    }

    @Pointcut("execution(public * com.handle..*Controller.*(..))")
    public void checkNull() {
    }

    @Around(value = "checkNull()")
    public Object check(ProceedingJoinPoint point) throws Throwable {
        Object obj;
        // 参数校验
        String msg = doCheck(point);
        if (!StringUtils.isEmpty(msg)) {
            return JsonResult.failure(HttpStatus.BAD_REQUEST.value(), msg);
        }
        obj = point.proceed();
        return obj;
    }

    /**
     * 参数校验
     *
     * @param point ProceedingJoinPoint
     * @return 错误信息
     */
    private String doCheck(ProceedingJoinPoint point) {
        // 获取方法参数值
        Object[] arguments = point.getArgs();
        // 获取方法
        Method method = getMethod(point);
        // 默认的错误信息
        String methodInfo = StringUtils.isEmpty(method.getName()) ? "" : "  方法名 " + method.getName();
        String msg = "";
        if (isCheck(method, arguments, CheckParam.class)) {
            CheckParam annotation = method.getAnnotation(CheckParam.class);
            String[] fields = annotation.value();
            // 只支持对第一个参数进行校验
            Object vo = arguments[0];
            if (vo == null) {
                msg = "param can not be null";
            } else {
                List<Object> list = new ArrayList<>();
                if (vo instanceof List) {
                    Object[] objs = ((List) vo).toArray();
                    for (Object o : objs) {
                        list.add(o);
                    }
                } else {
                    list.add(vo);
                }
                for (String field : fields) {
                    // 解析字段
                    try {
                        for (Object o : list) {
                            JSONObject jsonObject = JSONUtil.parseObj(JSONUtil.toJsonStr(o));
                            if (StringUtils.isEmpty(jsonObject.getStr(field))) {
                                return "属性:[" + field + "]不能为空";
                            }
                        }
                    } catch (Exception e) {
                        return "参数解析异常,请使用标准json格式";
                    }
                }
            }
        }
        return msg;
    }

}
